#include <iostream>
#include <leveldb/db.h>
#include <string>
#include <memory>
#include <leveldb/write_batch.h>
#include <leveldb/comparator.h>
#include <exception>

#define DB_PATH "/tmp/leveldb"

void MustOk(leveldb::Status &&s)
{
	if (!s.ok())
		throw std::runtime_error{"leveldb not ok"};
	else
		return;
}

class MyCmptor : public leveldb::Comparator
{
public:
	MyCmptor() = default;
	~MyCmptor() override
	{
	}

	int Compare(const leveldb::Slice &a, const leveldb::Slice &b) const override
	{
		return leveldb::BytewiseComparator()->Compare(b, a);
	}

	const char *Name() const override
	{
		return "My own cmptor";
	}

	void FindShortestSeparator(std::string *start, const leveldb::Slice &limit) const override
	{
	}

	void FindShortSuccessor(std::string *key) const override
	{
	}
};

int main(int argc, char **argv)
{
	std::cout << DB_PATH << std::endl;
	leveldb::Options opts;
	opts.create_if_missing = true;
	opts.comparator = new MyCmptor();

	leveldb::DB *dbptr = nullptr;

	leveldb::Status status = leveldb::DB::Open(opts, DB_PATH, &dbptr);
	if (status.ok())
	{
		std::cout << "leveldb open success" << std::endl;
	}
	else
	{
		std::cout << "failed to open db" << status.ToString() << std::endl;
	}

	std::unique_ptr<leveldb::DB> safedb{dbptr};

	leveldb::WriteOptions write_opt;
	write_opt.sync = false;
	leveldb::ReadOptions read_opt;
	read_opt.verify_checksums = false;

	MustOk(safedb->Put(write_opt, "apple", "apple"));
	MustOk(safedb->Put(write_opt, "pear", "pear"));
	MustOk(safedb->Put(write_opt, "jiba", "jiba"));
	MustOk(safedb->Put(write_opt, "code", "code"));
	MustOk(safedb->Put(write_opt, "women", "all slut"));

	// iterator how to use
	try
	{
		std::unique_ptr<leveldb::Iterator> it(safedb->NewIterator(leveldb::ReadOptions()));
		for (it->SeekToFirst(); it->Valid(); it->Next())
		{
			auto key = it->key().ToString();
			std::cout << "sorted key: " << key << " ";
		}
	}
	catch (...)
	{
	}

	std::cout << status.ToString() << std::endl;

	return 0;
}
